package com.lz.service.file;

import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.commonmark.Extension;
import org.commonmark.ext.gfm.tables.TableBlock;
import org.commonmark.ext.gfm.tables.TablesExtension;
import org.commonmark.ext.heading.anchor.HeadingAnchorExtension;
import org.commonmark.node.Link;
import org.commonmark.node.Node;
import org.commonmark.parser.Parser;
import org.commonmark.renderer.html.AttributeProvider;
import org.commonmark.renderer.html.AttributeProviderContext;
import org.commonmark.renderer.html.AttributeProviderFactory;
import org.commonmark.renderer.html.HtmlRenderer;
 
/**
 */
public class MarkdownToHtmlUtils {
 
    /**
     * markdown格式转换成HTML格式
     * @param markdown
     * @return
     */
    public static String markdownToHtml(String markdown) {
        Parser parser = Parser.builder().build();
        Node document = parser.parse(markdown);
        HtmlRenderer renderer = HtmlRenderer.builder().build();
        return renderer.render(document);
    }
 
    /**
     * 增加扩展[标题锚点，表格生成]
     * Markdown转换成HTML
     * @param markdown
     * @return
     */
    public static String markdownToHtmlExtensions(String markdown) {
        //h标题生成id
        Set<Extension> headingAnchorExtensions = Collections.singleton(HeadingAnchorExtension.create());
        //转换table的HTML
//        List<Extension> tableExtension = Arrays.asList(TablesExtension.create());
        List<Extension> tableExtension = Collections.singletonList(TablesExtension.create());
        Parser parser = Parser.builder()
                .extensions(tableExtension)
                .build();
        Node document = parser.parse(markdown);
        HtmlRenderer renderer = HtmlRenderer.builder()
                .extensions(headingAnchorExtensions)
                .extensions(tableExtension)
                .attributeProviderFactory(new AttributeProviderFactory() {
                    public AttributeProvider create(AttributeProviderContext context) {
                        return new CustomAttributeProvider();
                    }
                })
                .build();
        return renderer.render(document);
    }
 
    /**
     * 处理标签的属性
     */
    static class CustomAttributeProvider implements AttributeProvider {
        @Override
        public void setAttributes(Node node, String tagName, Map<String, String> attributes) {
            //改变a标签的target属性为_blank
            if (node instanceof Link) {
                attributes.put("target", "_blank");
            }
            if (node instanceof TableBlock) {
                attributes.put("class", "ui celled table");
            }
        }
    }
 
    public static void main(String[] args) throws IOException {
        String src = "## 接口的理解\n" +
                "\n" +
                "今天在做token加密这一块。用的网上的资料和之前用的资料。\n" +
                "\n" +
                "其中对于JwtUtil这个工具类有出入。\n" +
                "\n" +
                "在我为了完成小程序的任务时，就将小程序的JwtUtil的工具类导入了。\n" +
                "\n" +
                "但是并没有发现有异常。\n" +
                "\n" +
                "现在才理解了。他们都是做相同的业务，只是实现方式不同。然后对于运行前后的结果都是相同的。\n" +
                "\n" +
                "运行的过程可以不去关注。\n" +
                "\n" +
                "## 接口的理解新增\n" +
                "\n" +
                "我之前遇到的，模块化开发。欲调用其他模块的信息。就可以将模块的接口先写好。调用的时候就不会报错。\n" +
                "\n" +
                "之前的想法时注解镇压。\n" +
                "\n" +
                "## 返回头里面存放数据\n" +
                "\n" +
                "所以很适合做一个接口。来约束出参和入参。\n" +
                "\n" +
                "```java\n" +
                "*//* *将**token**添加入响应头以及返回用户信息\n" +
                "*response.setHeader(JWTUtils.*header*+\"----------e---------------\", \"设置响应头啦\");\n" +
                "```\n" +
                "\n" +
                "## 向返回头添加cookies数据\n" +
                "\n" +
                "```java\n" +
                " Cookie cookie = new Cookie(\"thisyokenpayh\", resultMap.get(\"token\").toString());\n" +
                "            cookie.setPath(\"/\");\n" +
                "            response.addCookie(cookie);\n" +
                "```\n" +
                "\n" +
                "### 当服务器在响应中返回`Set-Cookie`头部时，浏览器会自动保存这些Cookie值。浏览器会将这些Cookie存储在本地，以便在后续的请求中自动携带它们。\n" +
                "\n" +
                "## 起步设置数据库表信息需要考虑全面，或者拥有完整的需求。否则会需要多次更改\n" +
                "\n" +
                "\n" +
                "\n" +
                "使用注解注入value，可以统一改变值。**统一 很重要**\n" +
                "\n" +
                "```sql\n" +
                "CREATE TABLE tb_chessboard (\n" +
                "    board_id INT PRIMARY KEY AUTO_INCREMENT COMMENT '棋局的唯一标识符',\n" +
                "    player1 INT DEFAULT NULL COMMENT '玩家1号玩家id为int',\n" +
                "    player2 INT DEFAULT NULL COMMENT '玩家2号',\n" +
                "    player3 INT DEFAULT NULL COMMENT '玩家3号',\n" +
                "    player4 INT DEFAULT NULL COMMENT '玩家4号',\n" +
                "    game_type VARCHAR(255) DEFAULT NULL COMMENT '棋局类型',\n" +
                "    start_time DATETIME COMMENT '对局开始的日期和时间',\n" +
                "    end_time DATETIME COMMENT '对局结束的日期和时间',\n" +
                "    winner VARCHAR(20) COMMENT '胜利者',\n" +
                "    drop_records TEXT COMMENT '记录每个玩家在对局中的行动或操作',\n" +
                "    game_status VARCHAR(20) COMMENT '对局的当前状态，如进行中、已结束等',\n" +
                "    duration INT COMMENT '对局时长（以分钟为单位）',\n" +
                "    result VARCHAR(20) COMMENT '对局的结果，如胜利、失败、平局等'\n" +
                ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;\n" +
                "\n" +
                "```\n" +
                "\n" +
                "RequrstBody的作用？有些请求入参不使用RequrstBody，controller层也能识别是那个类，从而封装进去\n" +
                "\n" +
                "```\n" +
                "@RequestBody注解的作用是告诉Spring MVC框架将  请求体  中的数据绑定到方法参数上，以便我们可以方便地处理请求体中的数据。对于不同类型的请求，我们可以选择使用或不使用@RequestBody注解来适应不同的处理方式。\n" +
                "\n" +
                "他的作用就是读取请求体。\n" +
                "```\n" +
                "\n" +
                "MP的AUTO\n" +
                "\n" +
                "```\n" +
                "当使用AUTO主键生成策略时，可以不用手动传入主键值，MyBatis Plus会负责生成并赋值给实体对象的主键属性。如果手动传入主键值，MyBatis Plus会忽略传入的值，而是使用数据库生成的主键值。\n" +
                "```\n" +
                "\n" +
                "使用非对称加密就是将：验证token的任务，分发给客户端。 \n" +
                "\n" +
                "## 微服务的感觉就像是，将所有的服务全部解耦，可以独立使用，或修改，不会像之前那种藕断丝连的那样\n" +
                "\n" +
                "\n" +
                "\n" +
                "## 使用websocket时由于是多例所以注入时需要这种方式注入\n" +
                "\n" +
                "```java\n" +
                "GameService bean = (GameService) SpringContextUtil.*getBean*(\"GameService\");\n" +
                "int chessboardEntity = bean.add(game);\n" +
                "```\n" +
                "\n" +
                "\n" +
                "\n" +
                "### 使用pojo类时，尽量使用set注入数据，或者构建一个构造类（而不是使用全参构造数据）。因为在后期添加字段时，不会影响大局。倘若使用了全参构造，每次添加字段都会使后续修改代码。\n" +
                "\n" +
                "### 数据库中只有两种状态的数据，采用binyint格式保存。在bean使用boolean接收。mybstis会自动转化。\n" +
                "\n" +
                "Feign的包装优化\n" +
                "\n" +
                "## 优化包装\n" +
                "\n" +
                "这样丑陋的代码我们当然需要进行优化，优化的目标也很明确：**当我们通过Feign调用时，直接获取到实体对象，不需要额外的解装。而前端通过网关直接调用时，返回统一的包装体。**\n" +
                "\n" +
                "## maven的命令\n" +
                "\n" +
                "clean：\n" +
                "\n" +
                "install：打包文件到 out 目录\n" +
                "\n" +
                "package：会包含前几级的命令，并且打包到本地仓库。\n" +
                "\n" +
                "聚合与继承：聚合就是都是无父类。\n" +
                "\n" +
                "继承：存在父类。\n" +
                "\n" +
                "将某些环境添加如环境变量，是因为，文件夹里面存在可执行文件\n" +
                "\n" +
                "## MyBatis\n" +
                "\n" +
                "使用${}一般是给属性字段声明的\n" +
                "\n" +
                "#{}一般是给字段赋值的。\n" +
                "\n" +
                "在 MyBatis 中，`${}` 适用于动态拼接字段名或其他 SQL 片段，而 `#{}` 适用于传递参数值并生成占位符，以确保安全性和预编译处理。\n" +
                "\n" +
                "## Spring使用注解\n" +
                "\n" +
                "需要在著启动类上添加@EnableTransactionManagement从而开启事务\n" +
                "\n" +
                "\n" +
                "\n" +
                "## @RestController是将放回的结果转化成字符串吗\n" +
                "\n" +
                "## @RequestBody利用空参生成javaBean，利用反射机制填充内容。\n" +
                "\n" +
                "## 在集成MP时在Service层级时使用this.baseMapper代替自己注入的Mapper层。\n" +
                "\n" +
                "## 为什么在使用feign的时候需要给入参注解，比如就是@RequestPrarm\n" +
                "\n" +
                "## 前端传送的数据JSON和form-data，有什么区别？\n" +
                "\n" +
                "![image-20240607163455677](D:\\应用\\Typora\\图片\\image-20240607163455677.png)\n" +
                "\n" +
                "![image-20240607163439758](D:\\应用\\Typora\\图片\\image-20240607163439758.png)\n" +
                "\n" +
                "## 平时在MP写的两个string，他们的参数名不会映射,只会arg1，需要你配置@Pramer（name）\n" +
                "\n" +
                "\n" +
                "\n" +
                "创建表的时候，需要把筛选字段也保存进来（如果筛选字段是不变的话）\n" +
                "\n" +
                "\n" +
                "\n" +
                "## 使用swagger需要配置bean\n" +
                "\n" +
                "每个微服务需要不同的配置\n" +
                "\n" +
                "```java\n" +
                "@Configuration\n" +
                "@EnableSwagger2\n" +
                "public class SwaggerConfig {\n" +
                "\n" +
                "    //配置文档属性\n" +
                "    private ApiInfo getApiInfo() {\n" +
                "        return new ApiInfoBuilder().title(\"商品微服务接口文档\")\n" +
                "                .description(\"您好，前端\")\n" +
                "                .version(\"1.0\")\n" +
                "                .termsOfServiceUrl(\"http://www.baidu.com\")\n" +
                "                .build();\n" +
                "    }\n" +
                "\n" +
                "    //创建文档配置对象\n" +
                "    @Bean\n" +
                "    public Docket docket() {\n" +
                "        return new Docket(DocumentationType.SWAGGER_2)\n" +
                "                .apiInfo(getApiInfo())\n" +
                "                .groupName(\"group1\")\n" +
                "                .select()\n" +
                "                .build();\n" +
                "    }\n" +
                "}\n" +
                "```\n" +
                "\n" +
                "\n" +
                "\n" +
                "## MP的分页需要单独配置一个cfg\n" +
                "\n" +
                "```java\n" +
                "@Configuration\n" +
                "public class MyBatisPlusPageUtil {\n" +
                "\n" +
                "    @Bean\n" +
                "    public MybatisPlusInterceptor mybatisPlusInterceptor() {\n" +
                "        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();\n" +
                "        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));\n" +
                "        return interceptor;\n" +
                "    }\n" +
                "\n" +
                "}\n" +
                "```\n" +
                "\n" +
                "\n" +
                "\n" +
                "### 在使用springboot的时候，在controller层中设置的返回体的Map是公共的。然后在重复的使用Map后。会有些脏数据。未被覆盖。而返回至前端。\n" +
                "\n" +
                "\n" +
                "\n" +
                "## 使用@Requestbody读取一个字符串，返回整个json数据。\n" +
                "\n" +
                "\n" +
                "\n" +
                "## jeecgBoot前端无法寻找到资源\n" +
                "\n" +
                "首先，查看新增的包有没有导入，其次自己的mapper有没有写\n" +
                "\n" +
                "@MApper的优先级没有@MApperscan的优先级高\n" +
                "\n" +
                "![image-20240620235222196](C:\\Users\\12875\\Documents\\img\\image-20240620235222196.png)\n" +
                "\n" +
                "因为spring不支持向静态字段注入\n" +
                "\n" +
                "MP的pojo类的主键如果设置的是AUTO\n" +
                "\n" +
                "那么主键id在save时则不参与录入\n" +
                "\n" +
                "需要修改成input\n" +
                "\n" +
                "# 出现错误：Eureka注册失败\n" +
                "\n" +
                "## Cannot execute request on any known server\n" +
                "\n" +
                "解决方法：\n" +
                "\n" +
                "**最终解决：Eureka**服务的**defaultZone**地址必须要以/eureka结尾，不能以其他内容结尾（无论Server端还是Client端都是）\n" +
                "\n" +
                "BeanUtils无法传送继承泛型的id字段。\n" +
                "\n" +
                "## \n" +
                "\n" +
                "## 使用mybatisplus的分页插件，只能对一个查询使用。对于多个查询不知道total数量。\n" +
                "\n" +
                "\n" +
                "\n" +
                "Controller的接收入参是调用的无参方法，在使用set方法赋值。\n" +
                "\n" +
                "\n" +
                "\n" +
                "使用mybatis未查询到数据会返回一个内容未空但是不为null的类\n" +
                "\n" +
                "\n" +
                "\n" +
                "# 几种提高效率的方式\n" +
                "\n" +
                "1，使用多线程处理，数据库密集型任务。可以节省等待时间\n" +
                "\n" +
                "2，使用redis数据库缓存，某个接口的出参";
        System.out.println(markdownToHtmlExtensions(src));
    }
 
}
